package http

import (
	"fmt"
	"net/http"
	"reflect"

	"github.com/google/uuid"
	"go-api-template/internal/e"
	"go-api-template/service"
	"go.uber.org/zap"

	"github.com/gin-gonic/gin"
)

// Handle 请求接口包装方法
func Handle(r RequesterI) gin.HandlerFunc {
	return func(ctx *gin.Context) {

		// 非正常请求
		if ctx == nil {
			typeOfV := reflect.TypeOf(r).Elem()
			fmt.Printf("\t\ttype: %s \n", typeOfV.String())
			fmt.Printf("\t\tfiledNum: %d \n", typeOfV.NumField())
			fmt.Printf("\t\tRequest : \n")
			for i := 0; i < typeOfV.NumField(); i++ {
				field := typeOfV.Field(i)
				fmt.Printf("\t%s: %s\n", field.Name, field.Type)
			}
			return
		}

		// 创建一个新的 RequesterI, 避免将上一次的参数带到下一次当中
		if reflect.TypeOf(r).Kind() != reflect.Ptr {
			service.Log.Error("must be a pointer")
		}
		r := reflect.New(reflect.ValueOf(r).Elem().Type()).Interface().(RequesterI)

		resp, err := request(r, ctx)
		if resp == nil {
			service.Log.Sugar().Errorf("未知异常%+v", err.Error())
			ctx.JSON(http.StatusBadRequest, resp)
			return
		}

		// 错误统一处理（bad—request）
		if err != nil {
			if resp.Code != 0 {
				resp.Msg = resp.Msg + ": " + err.Error()
				ctx.JSON(http.StatusOK, resp)
				return
			}
			service.Log.Debug(err.Error())
			ctx.String(http.StatusBadRequest, err.Error())
			return
		}

		// 业务码为空时自动填充success code
		if resp.Code == 0 {
			resp.SetCode(e.Success)
		}

		// 自定义返回
		if _, ok := r.(CustomReturnI); !ok {
			// 标准返回结构
			ctx.JSON(http.StatusOK, resp)
			if service.Conf.Log.Response {
				service.Log.Info(fmt.Sprintf("返回参数: %+v", resp), zap.String("request_id", ctx.GetString("request_id")))
			}
		} else {
			ctx.JSON(http.StatusOK, resp)

		}
	}
}

// request 执行请求类接口实现
func request(r RequesterI, ctx *gin.Context) (*Resp, error) {
	// 参数绑定
	var err error
	var resp Resp

	// 创建服务层
	s := service.New()

	// 根据队列标识，写入接口队列
	if b, ok := r.(MqDoI); ok {
		queueId := uuid.New().String()
		service.Log.Sugar().Debugf("正在创建消息:%s", queueId)
		resp.SetData(map[string]string{
			"queue_id": queueId,
		})
		go b.PushMq(s, queueId)

		// TODO: 完善消费流程

		goto END
	}

	// 实现Binder接口执行Bind方法解析参数
	if b, ok := r.(BinderI); ok {
		err = b.Bind(ctx)
	} else {
		// 默认解析参数
		err = ctx.ShouldBind(r)
	}
	if err != nil {
		resp.SetCode(e.ParameterCheckFailed)
		goto END
	}

	// 优先缓存处理(基于缓存接口实现)
	// 基于URL路径写入缓存
	if b, ok := r.(PathCacheI); ok {
		cacheKey := e.DataPathCache + ctx.FullPath()
		resp, err = b.Cache(
			cacheKey,
			ctx,
			service.New(),
			service.SG,
		)
		goto END
	}

	// 基于路径+用户ID写入缓存
	if b, ok := r.(UserCacheI); ok {
		cacheKey := e.DataUserCache + ctx.FullPath() + fmt.Sprintf(":%s", ctx.GetString("user_id"))
		resp, err = b.UserCache(
			cacheKey,
			ctx,
			service.New(),
			service.SG,
		)
		goto END
	}

	// 执行实现，注入依赖
	resp, err = r.Request(ctx, s)

	// 记录请求日志
	if service.Conf.Log.Request {
		service.Log.Info(fmt.Sprintf("请求参数: %+v", r), zap.String("request_id", ctx.GetString("request_id")))
	}

END:
	return &resp, err
}
